package cn.joyfulmedia.controller.system.account;

import com.alibaba.fastjson.JSON;
import cn.joyfulmedia.common.util.CaptchaUtils;
import cn.joyfulmedia.common.util.Const;
import cn.joyfulmedia.controller.system.account.param.UpdatePwdParam;
import cn.joyfulmedia.entity.ExamMisAccount;
import cn.joyfulmedia.mis.service.interfaces.AccountService;
import cn.joyfulmedia.mis.service.interfaces.ResourcesService;
import cn.joyfulmedia.mis.utils.MisResponse;
import cn.joyfulmedia.shiro.ShiroSessionUtils;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.crypto.hash.Md5Hash;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.annotation.Resource;
import javax.imageio.ImageIO;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.HashMap;
import java.util.Map;

@Controller
public class LoginController {
    @Resource
    ResourcesService resourcesService;
    private Logger logger = LoggerFactory.getLogger(LoginController.class);
    @Resource
    private AccountService accountService;

    /**
     * 登陆页的映射
     *
     * @param model
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/")
    public String login(Model model) throws Exception {
        return "/login";
    }

    /**
     * 首页
     *
     * @param model
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/index")
    public String index(Model model) throws Exception {
        try {
            ExamMisAccount a = ShiroSessionUtils.getLoginAccount();
            model.addAttribute("user", a);
            model.addAttribute("resources",
                    resourcesService.findByAccountId(a.getId().longValue()));
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "/index";
    }

    @ResponseBody
    @RequestMapping(value = "/login.json")
    public Object loginPost(ExamMisAccount account, HttpServletRequest request, Model model) throws Exception {
        // type 类型用来标注会员类型,0表示普通会员
        Map<String, Object> map = new HashMap<String, Object>();
        map.put("status", -1);
        // 判断验证码
        /*
         * String code = (String)
		 * ShiroSessionUtils.getAttribute(Const.DEFAULT_CAPTCHA_PARAM); if
		 * (StringUtils.isNotBlank(code)) { code =
		 * code.toLowerCase().toString(); } String submitCode =
		 * WebUtils.getCleanParam(request, Const.DEFAULT_CAPTCHA_PARAM); if
		 * (StringUtils.isNotBlank(submitCode)) { submitCode =
		 * submitCode.toLowerCase().toString(); } if
		 * (StringUtils.isBlank(submitCode) || StringUtils.isBlank(code) ||
		 * !code.equals(submitCode)) { model.addAttribute("message", "验证码错误!");
		 * return "/login"; }
		 */

        UsernamePasswordToken token = new UsernamePasswordToken(
                account.getUsername(), account.getPassword());

        String rememberme = request.getParameter("rememberme");
        if (StringUtils.isNotBlank(rememberme)) {
            token.setRememberMe(true);
        } else {
            token.setRememberMe(false);
        }

        try {
            Subject subject = SecurityUtils.getSubject();
            subject.login(token);
            if (subject.isAuthenticated()) {
                ExamMisAccount a = ShiroSessionUtils.getLoginAccount();
                if (a.getForceChgPwd() == null || a.getForceChgPwd().intValue() != 1) { // 强制用户修改密码
                    map.put("status", 999331);
                    map.put("msg", "强制修改密码");
                    return map;
                }
                ExamMisAccount resultAccount = new ExamMisAccount();
                resultAccount.setNickName(a.getNickName());
                resultAccount.setUsername(a.getUsername());
                resultAccount.setLoginTime(a.getLoginTime());
                map.put("status", 0);
                map.put("data", resultAccount);
                map.put("msg", "登陆成功");
                return map;
            }
        } catch (UnknownAccountException uae) {
            map.put("msg", "账号不存在!");
        } catch (IncorrectCredentialsException ice) {
            // 密码不正确
            int num = (Integer) ShiroSessionUtils.getAttribute("loginNum");
            token.clear();
            map.put("msg", "用户名或密码错误,你还可以输入" + (5 - num) + "次");
        } catch (ExcessiveAttemptsException eae) {
            // 输入用户名或密码错误次数过多
            ShiroSessionUtils.setAsLogout();
            token.clear();
            map.put("msg", "输入用户名密码或次数过多,账户已被锁定,半小时后解锁");
        } catch (LockedAccountException lae) {
            map.put("msg", "账号被锁定!");
        } catch (Exception e) {
            e.printStackTrace();
            map.put("msg", "未知错误,请联系管理员.");
        }
        return map;
    }

    /**
     * 没有权限
     *
     * @param model
     * @return
     * @throws Exception
     */
    @RequestMapping(value = "/unauth")
    public String unauth(Model model) throws Exception {
        if (SecurityUtils.getSubject().isAuthenticated() == false) {
            return "redirect:/";
        }
        return "/unauth";

    }

    /**
     * 退出
     *
     * @param request
     */
    @RequestMapping(value = "/logout")
    public String logout(HttpServletRequest request) {
        Subject subject = SecurityUtils.getSubject();
        if (subject != null) {
            subject.logout();
        }
        return "/login";
    }

    /**
     * 生成验证码
     *
     * @return
     * @throws IOException
     */
    @RequestMapping("/getCaptcha")
    public void getCaptcha(HttpServletResponse response) throws IOException {

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.IMAGE_JPEG);

        CaptchaUtils tool = new CaptchaUtils();
        StringBuffer code = new StringBuffer();
        BufferedImage image = tool.genRandomCodeImage(code);
        ShiroSessionUtils.removeAttribute(Const.DEFAULT_CAPTCHA_PARAM);
        ShiroSessionUtils.setAttribute(Const.DEFAULT_CAPTCHA_PARAM,
                code.toString());

        // 将内存中的图片通过流动形式输出到客户端
        ImageIO.write(image, "JPEG", response.getOutputStream());
        return;
    }

    /**
     * 公共下载方法
     *
     * @param response
     * @param file     下载的文件
     * @param fileName 下载时显示的文件名
     * @return
     * @throws Exception
     */
    public HttpServletResponse downFile(HttpServletResponse response,
                                        File file, String fileName, boolean delFile) throws Exception {
        response.setContentType("application/x-download");
        response.setHeader("Pragma", "public");
        response.setHeader("Cache-Control",
                "must-revalidate, post-check=0, pre-check=0");
        OutputStream out = null;
        InputStream in = null;
        // 下面一步不可少
        fileName = new String(fileName.getBytes("GBK"), "ISO-8859-1");
        response.addHeader("Content-disposition", "attachment;filename="
                + fileName);// 设定输出文件头

        try {
            out = response.getOutputStream();
            in = new FileInputStream(file);
            int len = in.available();
            byte[] b = new byte[len];
            in.read(b);
            out.write(b);
            out.flush();

        } catch (Exception e) {
            logger.error(e.getMessage(), e);
            throw new Exception("下载失败!");
        } finally {
            if (in != null) {
                in.close();
            }
            if (out != null) {
                out.close();
            }
            if (delFile) {
                file.delete();
            }
        }

        return response;
    }

    @RequestMapping("/modify-login-pwd")
    public String modifyLoginPwd(Model model, HttpServletRequest request) {
        try {
            ExamMisAccount account = ShiroSessionUtils.getLoginAccount();
            Long id = account.getId().longValue();
            request.setAttribute("id", id);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "/update_password";
    }

    @RequestMapping("/update-pwd")
    @ResponseBody
    public Object updatePwd(UpdatePwdParam param) {
        Map<String, Object> map = MisResponse.getSuccessMap();
        try {
            System.out.println("更新密码参数：" + JSON.toJSONString(param));
            // 获取账户
            ExamMisAccount accountParam = accountService.selectAccountById(param.getId());
            System.out.println("查询出的账号：" + JSON.toJSONString(accountParam));
            if (accountParam != null) {
                String oldPwd = param.getOldPassword();
                String md5OldPwd = DigestUtils.md5Hex(oldPwd);
                if (!md5OldPwd.equals(accountParam.getPassword())) {
                    MisResponse.updateResponseMap(map, -1, "原密码错误");
                    return map;
                }

                String newPwd1 = param.getNewPassword();
                String newPwd2 = param.getNewPassword2();
                if (StringUtils.isBlank(newPwd1) || newPwd1.length() < 8) {
                    MisResponse.updateResponseMap(map, -1, "密码长度不能小于8位");
                }
                if (MisResponse.isSuccess(map)) {
                    if (StringUtils.isNotBlank(newPwd1) && newPwd1.equals(newPwd2)) {
//                accountController.checkPassword(account.getNew_password(), map);
                        if (MisResponse.isSuccess(map)) {
                            String newPwd = new Md5Hash(newPwd1).toString();
                            ExamMisAccount account = new ExamMisAccount();
                            account.setId(accountParam.getId());
                            account.setPassword(newPwd);
                            account.setForceChgPwd(1);
                            System.out.println("更新的数据：" + JSON.toJSONString(account));
                            int i = accountService.updateAccountById(account);
                            if (i <= 0) {
                                MisResponse.updateResponseMap(map, -1, "更新用户登录密码失败");
                            }
                        }
                    } else { // 两次输入的密码不匹配
                        MisResponse.updateResponseMap(map, -1, "两次输入的密码不匹配");
                    }
                }
            } else {
                MisResponse.updateResponseMap(map, -1, "没有找到指定ID的账号");
            }
        } catch (Exception e) {
            e.printStackTrace();
            MisResponse.updateResponseMap(map, -1, e.getMessage());
        }
        return map;
    }
}
